package cn.yeziji.forum.factory.websocket;

import cn.yeziji.forum.common.key.WebsocketCacheKey;
import cn.yeziji.forum.common.websocket.Chatroom;
import cn.yeziji.forum.dao.intf.ForumChatroomDao;
import cn.yeziji.forum.factory.websocket.enums.WebsocketFactoryOption;
import cn.yeziji.forum.service.websocket.WebsocketService;
import cn.yeziji.forum.utils.CacheUtils;
import cn.yeziji.forum.utils.NanoIdUtils;
import cn.yeziji.forum.utils.SpringUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.benmanes.caffeine.cache.Cache;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * websocket 操作超类
 *
 * @author gzkemays
 * @since 2022/3/27 14:34
 * @deprecated to netty
 */
@SuppressWarnings("unchecked")
public abstract class WebsocketOperationAbstract<T> {
  public static Integer JSON = 0;
  public static Integer JSON_ARRAY = 1;
  protected T params;
  protected Object additional;

  /**
   * 每个子类必须有默认执行的方法
   *
   * @return obj
   */
  protected abstract Object defaultMethod();

  public WebsocketOperationAbstract() {}

  public WebsocketOperationAbstract(Object data, Object additional) {
    if (additional != null) {
      this.additional = additional;
    }
    if (data != null) {
      params = (T) data;
    }
  }

  public WebsocketOperationAbstract(Object data) {
    if (data != null) {
      params = (T) data;
    }
  }

  /**
   * 反射实例化子类并执行 {@code option} 方法
   *
   * @param clazz extends {@link WebsocketFactoryOption} 子类
   * @param option 执行的方法
   * @return 执行结果
   */
  protected Object invoke(
      Class<? extends WebsocketOperationAbstract<T>> clazz, WebsocketFactoryOption option) {
    try {
      Method clazzMethod = clazz.getDeclaredMethod(option.getMethod());
      Constructor<? extends WebsocketOperationAbstract<T>> declaredConstructor;
      Object obj;
      if (additional != null) {
        declaredConstructor = clazz.getDeclaredConstructor(Object.class, Object.class);
        obj = declaredConstructor.newInstance(params, additional);
      } else {
        declaredConstructor = clazz.getDeclaredConstructor(Object.class);
        obj = declaredConstructor.newInstance(params);
      }
      clazzMethod.setAccessible(true);
      return clazzMethod.invoke(obj);
    } catch (NoSuchMethodException
        | IllegalAccessException
        | InstantiationException
        | InvocationTargetException e) {
      e.printStackTrace();
    }
    return null;
  }

  protected ForumChatroomDao getChatroomDao() {
    return SpringUtils.getBean(ForumChatroomDao.class);
  }

  protected Cache<String, String> getUserCache() {
    return SpringUtils.getBean("userWebsocketCache");
  }

  protected WebsocketService getWebsocketService() {
    return SpringUtils.getBean("websocketService");
  }

  /**
   * 发送消息给指定 name
   *
   * @param name 连接用户
   * @param message 发送的信息
   * @param parseMode 发送的类型
   */
  protected void send(String name, Object message, Integer parseMode) {
    if (params instanceof Chatroom) {
      Chatroom chatroom = (Chatroom) params;
      saveChatroomCache(chatroom);
      getWebsocketService().appointSending(name, buildMsg(message, parseMode));
    }
  }

  protected void saveChatroomCache(Chatroom chatroom) {
    String key = chatroom.getKey();
    String msg = chatroom.getMsg();
    if (key.equals(Chatroom.USER_MSG) && msg == null) {
      getDefaultCache().setHash(getCacheKey(), chatroom.getToken(), "online", 10, TimeUnit.MINUTES);
    } else if (msg != null) {
      getDefaultCache()
          .setHash(getCacheKey(), NanoIdUtils.randomNanoId(), chatroom, 10, TimeUnit.MINUTES);
    }
  }

  protected String getCacheKey() {
    if (params instanceof Chatroom) {
      Chatroom chatroom = (Chatroom) params;
      String key = chatroom.getKey();
      if (key.equals(Chatroom.USER_MSG)) {
        return WebsocketCacheKey.USER_ONLINE;
      } else if (key.equals(Chatroom.PRIVATE) || key.equals(Chatroom.SYSTEM)) {
        return WebsocketCacheKey.privateChatroom(chatroom.getChatroom());
      }
    }
    return null;
  }

  protected CacheUtils getCache(long time, TimeUnit timeUnit) {
    CacheUtils cache = SpringUtils.getBean(CacheUtils.class);
    cache.caffeineAddTime(time, timeUnit);
    return cache;
  }

  protected CacheUtils getDefaultCache() {
    return getCache(30, TimeUnit.SECONDS);
  }

  private String buildMsg(Object obj, Integer mode) {
    if (mode == JSON) {
      return JSONObject.toJSONString(obj);
    } else if (mode == JSON_ARRAY) {
      return JSONArray.toJSONString(obj);
    }
    throw new IllegalArgumentException("没有指定的转换模式，请参考 WebsocketOperationAbstract 中的静态变量值。");
  }
}
